/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.sensor.cropcircle;

import nl.cloudfarming.sensor.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.EnumMap;
import nl.cloudfarming.sensor.ParsedUnit;
import nl.cloudfarming.sensor.Parser;
import nl.cloudfarming.sensor.model.DataFileBO;
import nl.cloudfarming.sensor.model.GeoSensorDataBO;
import nl.cloudfarming.sensor.model.GeoSensorDataFileBO;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class CropCircleParser implements Parser<String> {

    private static Log log = LogFactory.getLog(CropCircleParser.class);
    private EnumMap map = new EnumMap<CropCircleFileDescription, Object>(CropCircleFileDescription.class);

    @Override
    public ParsedUnit parse(String payload, DataFileBO dataFileBO) throws ParseException {
        // First create a entity representation of a file
        //converting the differrent data
        String[] fields = payload.toString().split(CropCircleFileDescription.getDelimmiter());
        for (CropCircleFileDescription c : CropCircleFileDescription.values()) {
            if (c.isMandatory()) {
                if (c.getTheClass().equals(java.lang.Double.class)) {
                    double theDouble = parseDouble(fields[c.getPosition()], c.name());
                    map.put(c, theDouble);
                } else if (c.getTheClass().equals(java.lang.Integer.class)) {
                    int theInt = parseInt(fields[c.getPosition()], c.name());
                    map.put(c, theInt);
                } else if (c.getTheClass().equals(java.util.Date.class)) {
                    Date theDate = parseTime(fields[c.getPosition()], c.name());
                    map.put(c, theDate);
                } else {
                    map.put(c, fields[c.getPosition()]);
                }
            }
        }
        GeoSensorDataBO dataBO = new GeoSensorDataBO((GeoSensorDataFileBO) dataFileBO, (Double) map.get(CropCircleFileDescription.LONGITUDE), (Double) map.get(CropCircleFileDescription.LATITUDE), (Integer) map.get(CropCircleFileDescription.FIX_TYPE), (Date) map.get(CropCircleFileDescription.UTC_TIME), (Double) map.get(CropCircleFileDescription.SPEED), (Double) map.get(CropCircleFileDescription.COURSE), (Double) map.get(CropCircleFileDescription.SENSOR), (Double) map.get(CropCircleFileDescription.VI1), (Double) map.get(CropCircleFileDescription.VI2), (Double) map.get(CropCircleFileDescription.R1), (Double) map.get(CropCircleFileDescription.R2), (Double) map.get(CropCircleFileDescription.R3), (String) map.get(CropCircleFileDescription.APP_RATE));
        return dataBO;
    }

    /*
     * expects a string with delimiters. It checks length, number of records and if the field is mandatory.
     */
    @Override
    public boolean ableToParse(Object payload) {
        // This parser can only parse Strings
        if (!(payload instanceof String)) {
            return false;
        }
        int counter = 0;
        String field[] = (payload.toString().split(CropCircleFileDescription.getDelimmiter()));
        //check if the number of fields is greater than or equal to the number of mandatory fields and less than maximal number of fields
        if (field.length >= calculateNumberOfMandatoryFields() && field.length <= CropCircleFileDescription.values().length) {
            for (CropCircleFileDescription c : CropCircleFileDescription.values()) {
                if (c.isMandatory()) {
                    //check if field is not empty
                    if (field[counter].trim().equals("")) {
                        return false;
                    }
//                    //check if field is correct lenght
//                    if (c.getMandatoryLength() > field[counter].trim().length()) {
//                        return false;
//                    }
                }
                counter++;
            }
            return payload.toString().split(CropCircleFileDescription.getDelimmiter()).length >= calculateNumberOfMandatoryFields();
        }
        return false;
    }

    private double parseDouble(String doubleValue, String fieldName) throws ParseException {
        try {
            return Double.parseDouble(doubleValue);
        } catch (NumberFormatException e) {
            throw new ParseException("Cropcircle parser: Cannot convert '" + fieldName + "' value to java.lang.Double ", e);
        }
    }

    private int parseInt(String intValue, String fieldName) throws ParseException {
        try {
            return Integer.parseInt(intValue);
        } catch (NumberFormatException e) {
            throw new ParseException("Cropcircle parser: Cannot convert '" + fieldName + "' value to java.lang.Double ", e);
        }
    }

    private Date parseTime(String time, String fieldName) throws ParseException {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("HHmmss.SS");
            return sdf.parse(time);
        } catch (java.text.ParseException ex) {
            log.error("Cropcircle parser: Cannot convert '" + fieldName + "' value to java.lang.Date To Create a new Date");
            throw new ParseException(ex);
        }
    }

    /*
     * return the number of fields that are mandatory
     */
    public int calculateNumberOfMandatoryFields() {
        int counter = 0;
        for (CropCircleFileDescription c : CropCircleFileDescription.values()) {
            if (c.isMandatory()) {
                counter++;
            }
        }
        return counter;
    }
}
